﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace PServiceBus.Services.Gateway.Runtime {
    public class FilterExpression {
        private string _raw;
        private FilterExpression() { }
        public string Text { get; internal set; }
        public string Type { get; internal set; }
        public FilterExpression Left { get; internal set; }
        public FilterExpression Right { get; internal set; }
        public static FilterExpression Raw(string expression) {
            return new FilterExpression() { _raw = expression };
        }

        public static FilterExpression And(FilterExpression left, FilterExpression right) {
            return new FilterExpression() { Type = "&&", Left = left, Right = right };
        }

        public static FilterExpression Or(FilterExpression left, FilterExpression right) {
            return new FilterExpression() { Type = "||", Left = left, Right = right };
        }

        private static FilterExpression Condition(string oper, string property, object value) {
            var needQuotes = value is String || value is DateTime || value is TimeSpan ||
                value is Guid;
            var quote = needQuotes ? "\"" : string.Empty;
            return new FilterExpression()
            {
                Type = oper,
                Left = new FilterExpression() { Text = property },
                Right = new FilterExpression() { Text = String.Format("{0}{1}{0}", quote, value, quote) }
            };
        }

        public static FilterExpression Equal(string property, object value) {
            return Condition("=", property, value);
        }

        public static FilterExpression NotEqual(string property, object value) {
            return Condition("!=", property, value);
        }

        public static FilterExpression GreaterThan(string property, object value) {
            return Condition(">", property, value);
        }

        public static FilterExpression LessThan(string property, object value) {
            return Condition("<", property, value);
        }

        public static FilterExpression GreaterThanOrEqual(string property, object value) {
            return Condition(">=", property, value);
        }

        public static FilterExpression LessThanOrEqual(string property, object value) {
            return Condition("<=", property, value);
        }

        public static FilterExpression Contains(string property, string value) {
            return Condition("like", property, value);
        }

        public static FilterExpression Regex(string property, string value) {
            return Condition("regex", property, value);
        }

        private static void Walk(FilterExpression filter, StringBuilder sb) {
            if (filter == null) return;
            var hasOper = filter.Left != null && filter.Right != null;
            if (hasOper) {
                sb.Append("(");
                Walk(filter.Left, sb);
                sb.AppendFormat(" {0} ", filter.Type);
                Walk(filter.Right, sb);
                sb.Append(")");
            } else 
                sb.Append(filter.Text);
        }

        public override string ToString() {
            if (_raw != null) return _raw;
            var sb = new StringBuilder();
            Walk(this, sb);
            return sb.ToString();
        }
    }
}
